Control the Brightness of an LED


Use PWM to change the LED brightness

We previously used an LED as a digital output, switching the LED on and off.

In this recipe, we use a technique called Pulse Width Modulation (PWM) to control the brightness of the LED.

Build the Circuit

You will need:

Wire up the circuit as follows (this is exactly the same circuit we built for the flash an LED recipe):

Enter the Code

Copy the code below and overwrite the code in the Arduino IDE.

// Constants
const int LEDPIN = 9;

// Setup is run once
void setup() {
  // Tell Arduino which pins are input and output
  pinMode(LEDPIN, OUTPUT);
}

// Loop is run over and over again
void loop() {
  int i;

  // Turn brightness up gradually
  for (i=0; i<255; i++) {
    analogWrite(LEDPIN, i);   // set the brightness level
    delay(20);                // wait a bit to slow down the transition
  }
}
        

Run the Code

Now upload the code to the Arduino.

The LED should start flashing.

Try to get the LED brightness to gradually increase and then gradually decrease.

How it Works

In the Flash an LED sketch, we used the digitalWrite() function to turn the voltage on the pin on and off. Let's take a look at what's happening when we run that code:

digitalWrite(LEDPIN,HIGH);
delay(1000);
digitalWrite(LEDPIN,LOW);
delay(1000);

We can draw a chart showing the voltage on the y-axis and time on the x-axis. Each time we call digitalWrite() with the HIGH parameter, the voltage on the pin is set to the HIGH voltage (which is 5V for most Arduinos). Each time we call digitalWrite() with the LOW parameter, the voltage on the pin is set to the LOW voltage, which is 0V:

So that's digitalWrite(). PWM uses the analogueWrite() function. PWM works by turning the voltage on the pin on and off very rapidly (every couple of milliseconds). By adjusting the proportion of time the pin is high and low, the LED brightness can be adjusted.

If we have the pin HIGH for 50% of the time and LOW for 50% of the time, the LED appears to be around 50% of the full brightness. The voltage signal on the pin looks like this:

For each period of 2 milliseconds, the pin is HIGH for 50% of the time and LOW for 50% of the time. We say that we have a 50% duty cycle. We can set the pin to 50% duty cycle by calling analogWrite(LEDPIN, 127). The numeric parameter to the function is a value between 0 and 255, so 127 is half of 255, hence 50%.

If we set the duty cycle to 75%, by calling analogWrite(LEDPIN, 191) we can get 75% brightness:

Calling analogWrite(LEDPIN, 64) will give us 25% brightness:

Calling analogWrite(LEDPIN, 0) will give us 0% brightness:

Calling analogWrite(LEDPIN, 255) will give us 100% brightness:

Note that we are not setting the voltage on the pin to anything other than the HIGH or LOW voltage. E.g. on an Arduino Leonardo, where the HIGH voltage is 5V, the pin will be either 0V or 5V, never 3V or 2.5V. In this way, analogueWrite() is not outputting a true analogue signal. The name of the function is a bit misleading. It is effectively faking an analogue effect using PWM to switch the pin on and off very rapidly.

 

Only some of the Arduino pins support PWM. These are indicated by a tilde character ~ next to the pin number.